package com.changgou.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.changgou.common.pojo.Page;
import com.changgou.search.service.SearchService;
import com.changgou.service.pojo.SkuInfo;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ElasticsearchTemplate esTemplate;

    //设置每页查询条数据
    @Override
    public Map<String, Object> search(Map<String, String> searchMap) {
        Map<String, Object> resultMap = new HashMap<>();
        //有条件才查询Es
        if (ObjectUtil.isNotEmpty(searchMap)) {
            //组合条件对象
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            //0:关键词
            if (StrUtil.isNotEmpty(searchMap.get("keywords"))) {
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }
            //1:条件 品牌
            if (StrUtil.isNotEmpty(searchMap.get("brand"))) {
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }
            //2:条件 规格
            // 假设 searchMap 不为空
            searchMap.entrySet().stream()
                    .filter(entry -> StrUtil.startWith(entry.getKey(), "spec_"))
                    .forEach(entry ->
                            boolQuery.filter(QueryBuilders.termQuery(StrUtil.format("specMap.{}.keyword", StrUtil.sub(entry.getKey(), 5, -1)), StrUtil.replace(entry.getValue(), "+", "%2B")))
                    );
            //3:条件 价格
            if (StrUtil.isNotEmpty(searchMap.get("price"))) {
                List<String> split = StrUtil.split(searchMap.get("price"), "-");
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(CollUtil.getFirst(split)));
                if (ObjectUtil.equal(split.size(), 2)) {
                    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(CollUtil.getLast(split)));
                }
            }
            //4. 原生搜索实现类
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            nativeSearchQueryBuilder.withQuery(boolQuery);
            //5:高亮
            HighlightBuilder.Field field = new HighlightBuilder
                    .Field("name")
                    .preTags("<span style='color:red'>")
                    .postTags("</span>");
            nativeSearchQueryBuilder.withHighlightFields(field);
            //6. 品牌聚合(分组)查询
            String skuBrand = "skuBrand";
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));
            //7. 规格聚合(分组)查询
            String skuSpec = "skuSpec";
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));
            //8: 排序
            if (StrUtil.isNotEmpty(searchMap.get("sortField"))) {
                if (StrUtil.equals("DESC", searchMap.get("sortRule"))) {
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(searchMap.get("sortField")).order(SortOrder.ASC));
                } else {
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(searchMap.get("sortField")).order(SortOrder.DESC));
                }
            }
            String pageNum = searchMap.get("pageNum");
            if (ObjectUtil.isEmpty(pageNum)) {
                pageNum = "1";
            }
            //9: 分页
            nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.parseInt(pageNum) - 1, Page.pageSize));
            //10: 执行查询, 返回结果对象
            AggregatedPage<SkuInfo> aggregatedPage = esTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
                @Override
                public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                    List<T> list = new ArrayList<>();
                    SearchHits hits = searchResponse.getHits();
                    if (ObjectUtil.isNotEmpty(hits)) {
                        list = Arrays.stream(hits.getHits())  // 如果 hits 是 SearchHit[] 数组
                                .map(hit -> {
                                    SkuInfo skuInfo = JSONUtil.toBean(hit.getSourceAsString(), SkuInfo.class);
                                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                                    if (ObjectUtil.isNotEmpty(highlightFields)) {
                                        skuInfo.setName(StrUtil.toString(ArrayUtil.get(highlightFields.get("name").getFragments(), 0)));
                                    }
                                    return (T) skuInfo;
                                })
                                .collect(Collectors.toList());
                    }
                    return new AggregatedPageImpl<T>(list, pageable, hits.getTotalHits(), searchResponse.getAggregations());
                }
            });
            //11. 总条数
            resultMap.put("total", aggregatedPage.getTotalElements());
            //12. 总页数
            resultMap.put("totalPages", aggregatedPage.getTotalPages());
            //13. 查询结果集合
            resultMap.put("rows", aggregatedPage.getContent());
            //14. 获取品牌聚合结果
            StringTerms brandTerms = BeanUtil.toBean(aggregatedPage.getAggregation(skuBrand), StringTerms.class);
            List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("brandList", brandList);
            //15. 获取规格聚合结果
            StringTerms specTerms = BeanUtil.toBean(aggregatedPage.getAggregation(skuSpec), StringTerms.class);
            List<String> specList = specTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
            resultMap.put("specList", specList(specList));
            //16. 返回当前页
            resultMap.put("pageNum", pageNum);
            return resultMap;
        }
        return null;
    }

    //处理规格集合
    public Map<String, Set<String>> specList(List<String> specList) {
        Map<String, Set<String>> specMap = new HashMap<>();
        if (CollUtil.isNotEmpty(specList)) {
            specList.stream()
                    .map(JSONUtil::parseObj)
                    .flatMap(map -> map.entrySet().stream())
                    .forEach(entry -> {
                        String key = entry.getKey();
                        String value = StrUtil.toString(entry.getValue());
                        specMap.computeIfAbsent(key, k -> new HashSet<>()).add(value);
                    });
        }
        return specMap;
    }
}
